﻿/**
* @description  Slide instance that can hold a number of nested slides, but does not render itself.
*/
package com.foed.applications.slideshow.slides {

	import com.foed.applications.slideshow.SlideShow;
	import com.foed.applications.slideshow.SlideProperties;
	import com.foed.events.SlideShowEvent;

	public class SlideCollection extends Slide {
	
		static public var sProperties:SlideProperties;

		private var _currentIndex:int;
		private var _slides:XMLList;
		private var _currentSlide:Slide;
		private var _nextSlide:Slide;
	
		/**
		* @description  Constructor.
		*
		* @param  pSlideData  The XML defining a slide instance.
		* @param  pSlideShow  The main slide show application.
		*/
		public function SlideCollection(pSlideData:XML, pSlideShow:SlideShow) {
			super(pSlideData, pSlideShow);
		}
	
		/**
		* @description  Initializes slide and its properties, drawing its background and graphics when necessary.
		*
		* @param  pSlideData  The XML defining a slide instance.
		* @param  pSlideShow  The main slide show application.
		*/
		override protected function init(pSlideData:XML, pSlideShow:SlideShow):void {
			super.init(pSlideData, pSlideShow);
			_currentIndex = -1;
			_slides = pSlideData.children();
		}
	
		/**
		* @description  Event handler for when a timed slide completes its time to display.
		*
		* @param  pEvent  Event fired by Slide.
		*/
		private function onTimedSlideComplete(pEvent:SlideShowEvent):void {
			_currentSlide.removeEventListener(SlideShowEvent.TIMED_SLIDE_COMPLETE, onTimedSlideComplete);
			displayNextSlide();
		}
	
		/**
		* @description  Event handler for when a slide completes its reveal on screen.
		*
		* @param  pEvent  Event fired by Slide.
		*/
		private function onSlideRevealComplete(pEvent:SlideShowEvent):void {
			_locked = false;
			removeCurrentSlide();
			_nextSlide.removeEventListener(SlideShowEvent.SLIDE_REVEAL_COMPLETE, onSlideRevealComplete);
			_currentSlide = _nextSlide;
			if (!_currentSlide.timed && (timed > 0)) {
				_currentSlide.time = _time;
			}
			if (_currentSlide.timed) {
				_currentSlide.addEventListener(SlideShowEvent.TIMED_SLIDE_COMPLETE, onTimedSlideComplete);
				_currentSlide.startCountdown();
			}
		}
	
		/**
		* @description  Instantiates and reveals the specified slide in the collection.
		*
		* @param  pIndex  The index in the collection list containing the slide to reveal.
		*/
		private function displaySlide(pIndex:uint):void {
			if (pIndex >= _slides.length() || pIndex < 0) return;
			_locked = true;
			if (_currentSlide) {
				_currentSlide.removeEventListener(SlideShowEvent.TIMED_SLIDE_COMPLETE, onTimedSlideComplete);
			}
			_nextSlide = SlideFactory.createSlide(_slides[pIndex], _slideShow);
			_nextSlide.masterSlide = this;
			_nextSlide.addEventListener(SlideShowEvent.SLIDE_REVEAL_COMPLETE, onSlideRevealComplete);
			_nextSlide.reveal();
		}
	
		/**
		* @description  Removes the current slide from the display list and the slide show.
		*/
		private function removeCurrentSlide():void {
			if (_currentSlide) {
				_currentSlide.removeEventListener(SlideShowEvent.TIMED_SLIDE_COMPLETE, onTimedSlideComplete);
				_currentSlide.remove();
				if (_content && _content.contains(_currentSlide)) {
					_content.removeChild(_currentSlide);
				}
			}
		}
	
		/**
		* @description  Triggers a slide to reveal itself, using its appropriate transition.
		*				For a collection, the reveal is passed to its first slide.
		*/
		override public function reveal():void {
			super.reveal();
			displayNextSlide();
		}

		/**
		* @description  Causes the previous slide to render. To be overridden by child classes.
		*/
		override public function displayPreviousSlide():void {
			if (_locked) return;
			if (hasPreviousSlide()) {
				if (_currentSlide && _currentSlide.hasPreviousSlide()) {
					if (!_currentSlide.locked) _currentSlide.displayPreviousSlide();
				} else {
					displaySlide(--_currentIndex);
				}
			} else if (_master && _master.hasPreviousSlide()) {
				_master.displayPreviousSlide();
			}
		}
	
		/**
		* @description  Causes the next slide to render. To be overridden by child classes.
		*/
		override public function displayNextSlide():void {
			if (_locked) return;
			if (hasNextSlide()) {
				if (_currentSlide && _currentSlide.hasNextSlide()) {
					if (!_currentSlide.locked) _currentSlide.displayNextSlide();
				} else {
					displaySlide(++_currentIndex);
				}
			} else if (_master && _master.hasNextSlide()) {
				_master.displayNextSlide();
			}
		}
			
		/**
		* @description  Returns whether there is a subsequent slide to render after the current slide.
		*
		* @returns  True if there is a subsequent slide to render.
		*/
		override public function hasNextSlide():Boolean {
			if (_currentSlide && _currentSlide.hasNextSlide()) return true;
			return _currentIndex < _slides.length()-1;
		}
	
		/**
		* @description  Returns whether there is a previous slide to render before the current slide.
		*
		* @returns  True if there is a previous slide to render.
		*/
		override public function hasPreviousSlide():Boolean {
			if (_currentSlide && _currentSlide.hasPreviousSlide()) return true;
			return _currentIndex > 0;
		}
	
		/**
		* @description  Removes a slide, clears timers and nulls content.
		*/
		override public function remove():void {
			removeCurrentSlide();
			if (_nextSlide) {
				_nextSlide.removeEventListener(SlideShowEvent.SLIDE_REVEAL_COMPLETE, onSlideRevealComplete);
				_nextSlide.remove();
			}
			super.remove();
		}

	}

}